// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;
using System.Collections.Generic;
using System.Linq;

namespace SnapObjects.Data
{
    internal abstract class SqlBuildStatement : ICloneable<SqlBuildStatement>
    {
        protected int _version = 0;
        protected IDictionary<string, ISqlBuilderParameter> _parameters;
        protected ParameterNameGenerator _nameGenerator;

        public SqlBuildStatement()
        {
            _parameters = new Dictionary<string, ISqlBuilderParameter>(StringComparer.OrdinalIgnoreCase);
            _nameGenerator = new ParameterNameGenerator();
        }

        public ISqlBuilderParameter[] Parameters => _parameters.Values.ToArray();

        public abstract SqlStatementType StatementType { get; }

        public int Version => _version;

        public string GetParameterPlacehold(string name)
        {
            if (_parameters.TryGetValue(name, out var parameter))
            {
                return parameter.PlaceholdName;
            }

            throw new KeyNotFoundException($"Undefined parameter '{name}'.");
        }

        protected void OnChanged(ISqlParameter parameter)
        {
            _version++;

            if (parameter != null)
            {
                this.AddParameters(parameter);
            }
        }

        public ISqlParameter AddParameter(string name, Type dataType, string prefix = "")
        {
            if (!_parameters.TryGetValue(name, out var parameter))
            {
                var placeholdName = String.Format(SqlBuilder.SQL_PLACEHOLD_FORMAT, prefix, name);

                parameter = new SqlBuilderParameter(placeholdName, name, dataType);

                _parameters.Add(name, parameter);
            }

            return parameter;
        }

        public bool AddParameters(params ISqlParameter[] parameters)
        {
            var result = false;

            foreach (var parameter in parameters)
            {
                var param = (SqlBuilderParameter)parameter;

                if (String.IsNullOrWhiteSpace(param.Name))
                {
                    param.Name = _nameGenerator.GenerateNext();

                    if (_parameters.ContainsKey(param.Name))
                    {
                        param.Name = _nameGenerator.GenerateNext();
                    }
                }

                if (!_parameters.ContainsKey(param.Name))
                {
                    if (String.IsNullOrWhiteSpace(param.PlaceholdName))
                    {
                        var prefix = parameter.GetHashCode().ToString().Replace('-', '_');

                        param.PlaceholdName = String.Format(SqlBuilder.SQL_PLACEHOLD_FORMAT, prefix, param.Name);
                    }

                    _parameters.Add(param.Name, param);

                    result = true;
                }
            }

            return result;
        }

        public void RemoveAllParameters()
        {
            _parameters.Clear();
            _version = 0;
        }

        public virtual void Clear()
        {
            _parameters.Clear();
            _version = 0;
        }

        public abstract SqlBuildStatement Clone();
    }
}
